package com.smilive.start.netty.jdk;

import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: netty_start
 * @Date: 2022-01-04 9:54
 * @Author: smilive
 * @Description: java.nio 文件操作
 */
public class FileOperateTest {

    public static void main(String[] args) throws IOException {

        test08();
    }

    /**
     *  使用Files工具类中的walkFileTree(Path, FileVisitor) 遍历访问资源
     *  FileVisitor：文件访问器，使用访问者模式
     * 接口的实现类SimpleFileVisitor有四个方法
     * preVisitDirectory：访问目录前的操作
     * visitFile：访问文件的操作
     * visitFileFailed：访问文件失败时的操作
     * postVisitDirectory：访问目录后的操作
     * @throws IOException
     */
    private static void test08() throws IOException {
        Path path = Paths.get("D:\\smilive-police");
        // 文件目录数目
        AtomicInteger dirCount = new AtomicInteger();
        // 文件数目
        AtomicInteger fileCount = new AtomicInteger();
        Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println("文件目录:"+dir);
                // 增加文件目录数
                dirCount.incrementAndGet();
                return super.preVisitDirectory(dir, attrs);
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println("文件:"+file);
                // 增加文件数
                fileCount.incrementAndGet();
                return super.visitFile(file, attrs);
            }
        });
        // 打印数目
        System.out.println("文件目录数:"+dirCount.get());
        System.out.println("文件数:"+fileCount.get());
    }

    /**
     *  删除资源
     * @throws IOException
     */
    private static void test07() throws IOException {
        //删除文件
        Path source = Paths.get("smilove/targetByteBuffer.txt");
        //如果文件不存在，会抛异常 NoSuchFileException
        Files.delete(source);

        //删除目录
        Path target = Paths.get("smilove/d1");
        //如果目录还有内容，会抛异常 DirectoryNotEmptyException
        Files.delete(target);
    }

    /**
     *  移动文件
     *  StandardCopyOption.ATOMIC_MOVE 保证文件移动的原子性
     * @throws IOException
     */
    private static void test06() throws IOException {
        //移动文件
        Path source = Paths.get("targetByteBuffer.txt");
        //目标文件夹不存在 java.nio.file.NoSuchFileException: targetByteBuffer.txt -> hello\1.txt
        //Files.move(source,Paths.get("hello/1.txt"),StandardCopyOption.ATOMIC_MOVE);
        Files.move(source,Paths.get("smilove/targetByteBuffer.txt"),StandardCopyOption.ATOMIC_MOVE);

    }

    /**
     *  复制文件
     * @throws IOException
     */
    private static void test05() throws IOException {
        Path source = Paths.get("newByteBuffer.txt");
        Path target = Paths.get("targetByteBuffer.txt");
        //如果文件已存在，会抛异常 FileAlreadyExistsException
        Files.copy(source,target);
        //如果希望用 source 覆盖掉 target，需要用 StandardCopyOption 来控制
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

    }

    /**
     * Files 创建文件夹
     */
    private static void test04() throws IOException {
        Path path = Paths.get("smilive");
        //判断文件是否存在
        System.out.println(Files.exists(path));

        //创建一级目录,如果目录已存在，会抛异常 FileAlreadyExistsException
        //不能一次创建多级目录，否则会抛异常 NoSuchFileException
        Files.createDirectory(path);

        Files.createDirectories(Paths.get("smilove/d1/d2"));
    }

    /**
     * Path 用来表示文件路径
     * Paths 是工具类，用来获取 Path 实例
     */
    private static void test03() {
        // 相对路径 不带盘符 使用 user.dir 环境变量来定位 newByteBuffer.txt
        Path source = Paths.get("newByteBuffer.txt");
        System.out.println(Files.exists(source));

        Path source02 = Paths.get("d:\\1.txt"); // 绝对路径 代表了  d:\1.txt 反斜杠需要转义

        Path source03 = Paths.get("d:/1.txt"); // 绝对路径 同样代表了  d:\1.txt

        Path source04 = Paths.get("d:\\smilive-police", "com"); // 代表了  d:\data\projects
        System.out.println(Files.exists(source04));
    }

    /**
     * 当文件大于2G时
     */
    private static void test02() {
        try(
                FileChannel fin = new FileInputStream(ResourceUtils.getURL("classpath:").getPath() + File.separator + "byteBuffer.txt").getChannel();
                FileChannel fou = new FileOutputStream("newByteBuffer.txt").getChannel()
        ) {
            long size = fin.size();
            long capacity = fin.size();
            while (capacity > 0){
                capacity -= fin.transferTo(size-capacity, capacity, fou);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用transferTo方法可以快速、高效地将一个channel中的数据传输到另一个channel中，但一次只能传输2G的内容
     * transferTo底层使用了零拷贝技术
     */
    private static void test01() {
        try(
                FileChannel fin = new FileInputStream(ResourceUtils.getURL("classpath:").getPath() + File.separator + "byteBuffer.txt").getChannel();
                FileChannel fou = new FileOutputStream("newByteBuffer.txt").getChannel()
            ) {
            // 参数：inputChannel的起始位置，传输数据的大小，目的channel
            // 返回值为传输的数据的字节数
            // transferTo一次只能传输2G的数据
            fin.transferTo(0, fin.size(), fou);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
